﻿using System;
using System.Collections.Generic;
using UnityEngine;
using FairyGUI;

// TODO WG 缓存问题还未处理
namespace YanhuaMMO
{
    public class UIPackageResManager
    {
        private List<UIPackageRes> mLoadedPackageList = new List<UIPackageRes>();                                       // 当前加载的包
        private Dictionary<string, UIPackageRes> mUIToPackageList = new Dictionary<string, UIPackageRes>();             // 已加载UI对应的包    依赖关系
        private Dictionary<UIPackageRes, List<string>> mPackageToUIList = new Dictionary<UIPackageRes, List<string>>(); // 已加载的包对应UI    被依赖关系

        // 由于界面流程是先关闭后打开，会导致同一份资源先卸载然后加载，为了避免这种情况，卸载时等到下一帧
        private List<string> mCacheUIPackageNameList = new List<string>();

        private static UIPackageResManager mInstance;
        public static UIPackageResManager Instance 
        {
            get 
            {
                if (mInstance == null)
                    mInstance = new UIPackageResManager();
                return mInstance;
            }
        }

        public UIPackageResManager()
        {
            UIObjectFactory.SetLoaderExtension(typeof(CustomGLoader));
        }

        /// <summary>
        /// 加载资源
        /// . 加载包
        /// .. 加载依赖包
        /// ... 加载资源
        /// </summary>
        /// <param name="packageName">包名</param>
        /// <param name="resName">包中资源名</param>
        /// <param name="finishCall">加载完成后的回调</param>
        public void LoadRes(string packageName, string resName, Action<GComponent> finishCall)
        {
            packageName = GetRealPackageName(packageName);

            //1 是否直接加载过包
            string packageResPath = GetPackageResPath(packageName, resName);
            if (mUIToPackageList.ContainsKey(packageResPath)) 
            {
                if (Util.UIPackageResLog > 0) Debug.Log("[LoadFGUI][UIPackageResManager.LoadRes] loaded " + packageName + "." + resName);
                mUIToPackageList[packageResPath].LoadRes(resName, finishCall);
                return;
            }

            //2 是否间接加载过包
            foreach (UIPackageRes packageItem in mUIToPackageList.Values) 
            {
                if (packageItem != null && packageItem.packageName == packageName) 
                {
                    if (Util.UIPackageResLog > 0) Debug.Log("[LoadFGUI][UIPackageResManager.LoadRes] loading " + packageName + "." + resName);
                    AddUIDepend(packageResPath, packageItem);
                    packageItem.LoadRes(resName, finishCall);
                    return;
                }
            }

            // 3 加载包
            if (Util.UIPackageResLog > 0) Debug.Log("[LoadFGUI][UIPackageResManager.LoadRes] load " + packageName + "." + resName);
            UIPackageRes package = GetUIPackageRes(packageName);
            AddUIDepend(packageResPath, package);
            package.LoadPackage();
            package.LoadRes(resName, finishCall);
        }

        /// <summary>
        /// 卸载资源 
        /// .卸载自身
        /// ..卸载依赖
        /// </summary>
        /// <param name="packageName">包名</param>
        /// <param name="resName">包中资源名</param>
        public void UnLoadRes(string packageName, string resName)
        {
            packageName = GetRealPackageName(packageName);

            if (Util.UIPackageResLog > 0) Debug.Log("[LoadFGUI][UIPackageResManager.UnLoadRes] " + packageName + "." + resName);

            string packageResPath = GetPackageResPath(packageName, resName);
            UIPackageRes uiPackage = RemoveUIDepend(packageResPath);
            if (uiPackage == null) return;

            if (mPackageToUIList[uiPackage].Count == 0) 
            {
                // 无引用 走卸载流程
                uiPackage.UnLoadPackage();
            }
        }

        /// <summary>
        /// 返回一个key，用于类头部定义的字典中
        /// </summary>
        /// <param name="packageName">包名</param>
        /// <param name="res">包中资源名</param>
        /// <returns></returns>
        private string GetPackageResPath(string packageName, string res)
        {
            packageName = GetRealPackageName(packageName);

            return packageName + "_" + res;
        }

        // 增加UI和包之间的关系
        private void AddUIDepend(string cacheKey, UIPackageRes package) 
        {
            if (!mUIToPackageList.ContainsKey(cacheKey)) mUIToPackageList[cacheKey] = package;
            if (!mPackageToUIList.ContainsKey(package)) mPackageToUIList[package] = new List<string>();
            if (!mPackageToUIList[package].Contains(cacheKey)) mPackageToUIList[package].Add(cacheKey);
        }

        // 删除UI和包之间的关系
        private UIPackageRes RemoveUIDepend(string cacheKey)
        {
            if (!mUIToPackageList.ContainsKey(cacheKey)) return null;

            UIPackageRes uiPackage = mUIToPackageList[cacheKey];
            mUIToPackageList.Remove(cacheKey);
            List<string> dependList = mPackageToUIList[uiPackage];
            dependList.Remove(cacheKey);
            return uiPackage;
        }

        // 增加加载的包
        public void AddUIPackageRes(UIPackageRes res) 
        {
            if (mLoadedPackageList.Contains(res)) return;
            mLoadedPackageList.Add(res);
        }

        // 删除加载的包
        public void RemoveUIPackageRes(UIPackageRes res) 
        {
            if (!mLoadedPackageList.Contains(res)) return;
            mLoadedPackageList.Remove(res);
        }

        // 获取包得载体 TODO WG 后期缓存在这里做
        public UIPackageRes GetUIPackageRes(string packageName , bool isCreate = true) 
        {
            packageName = GetRealPackageName(packageName);

            for (int i = 0; i < mLoadedPackageList.Count; i++) 
            {
                if (mLoadedPackageList[i].packageName == packageName)
                    return mLoadedPackageList[i];
            }
            return isCreate ? new UIPackageRes(packageName) : null;
        }

        // 是否被UI依赖着
        public bool IsBedepend(string packageName) 
        {
            packageName = GetRealPackageName(packageName);

            foreach (var item in mPackageToUIList.Keys) 
            {
                if (item.packageName == packageName && mPackageToUIList[item].Count > 0)
                    return true;
            }
            return false;
        }

        // FUI加载需要的包名称
        private string GetRealPackageName(string packageName)
        {
            string realPackageName = packageName;
            if (realPackageName.IndexOf("FUI") == -1)
                realPackageName = "FUI/" + realPackageName;
            return realPackageName;
        }

        public UIPackage GetCacheUIPackage(string packageName) 
        {
            UIPackage uIPackage = UIPackage.GetById(packageName);
            if (uIPackage == null)
                uIPackage = UIPackage.AddPackage(packageName);
            mCacheUIPackageNameList.Remove(packageName);

            return uIPackage;
        }
        public void CacheUIPackage(string packageName) 
        {
            if (mCacheUIPackageNameList.Contains(packageName)) return;
            mCacheUIPackageNameList.Add(packageName);
        }

        public void RemoveCacheUIPackage() 
        {
            if (mCacheUIPackageNameList.Count == 0) return;

            for (int i = 0; i < mCacheUIPackageNameList.Count; i++)
            {
                UIPackage.RemovePackage(mCacheUIPackageNameList[i]);
            }

            mCacheUIPackageNameList.Clear();
        }

        public void Update() 
        {
            RemoveCacheUIPackage();
        }

        /// <summary>
        /// 主动增加依赖 出现这种情况的原因是UI中会主动增加依赖关系
        /// </summary>
        public void AddCustomUIPackageDepend(string packageName , string dependPackageName) 
        {
            UIPackageRes res = GetUIPackageRes(packageName);
            if (res == null) return;
            UIPackageRes dependRes = GetUIPackageRes(dependPackageName);
            res.AddDepend(dependRes);       // 依赖
            dependRes.AddBeDepend(res);     // 被依赖
            dependRes.LoadPackage();
        }
    }

    public class UIPackageRes
    {
        public string packageName;
        private List<UIPackageRes> dependPachageList = new List<UIPackageRes>();        // 依赖关系
        private List<UIPackageRes> beDependPachageList = new List<UIPackageRes>();      // 被依赖关系

        public UIPackageRes(string name) 
        {
            packageName = name;
        }

        // 加载包 并且递归加载依赖包
        public void LoadPackage() 
        {
            UIPackageResManager.Instance.AddUIPackageRes(this);
            // 已加载
            UIPackage loadedPackage = UIPackage.GetById(packageName);
            if (loadedPackage != null) 
            {
                UIPackageResManager.Instance.GetCacheUIPackage(packageName);
                return;
            }

            // 加载
            if (Util.UIPackageResLog > 0) Debug.Log("[LoadFGUI][UIPackageRes.LoadPackage] " + packageName);
            loadedPackage = UIPackageResManager.Instance.GetCacheUIPackage(packageName);
			if (loadedPackage == null) return;
            foreach (var depend in loadedPackage.dependencies)
            {
                UIPackageRes packageRes = UIPackageResManager.Instance.GetUIPackageRes(depend["name"]);
                if (Util.UIPackageResLog > 0) Debug.Log("[LoadFGUI][UIPackageRes.LoadPackage] try " + packageRes.packageName + " inpackage " + packageName);
                AddDepend(packageRes);         // 依赖
                packageRes.AddBeDepend(this);  // 被依赖
                packageRes.LoadPackage();
            }
        }

        // 卸载包 并且递归卸载依赖包
        public void UnLoadPackage() 
        {
            if (IsBeDepend() || UIPackageResManager.Instance.IsBedepend(packageName)) return;
            UIPackageResManager.Instance.RemoveUIPackageRes(this);

            if (Util.UIPackageResLog > 0) Debug.Log("[LoadFGUI][UIPackageRes.UnLoadPackage] " + packageName);
            if (UIPackage.GetById(packageName) != null)
                UIPackageResManager.Instance.CacheUIPackage(packageName);

            foreach (UIPackageRes packageRes in dependPachageList)
            {
                if (Util.UIPackageResLog > 0) Debug.Log("[LoadFGUI][UIPackageRes.UnLoadPackage] try " + packageRes.packageName + " inpackage " + packageName);
                packageRes.RemoveBeDepend(this);
                packageRes.UnLoadPackage();
            }
        }

        // 加载资源 包已经加载好了之后
        public void LoadRes(string resName, Action<GComponent> finishCall) 
        {
            if (Util.UIPackageResLog > 0)
            {
                Debug.Log("[LoadFGUI][UIPackageRes.LoadRes] " + packageName + "." + resName);
            }
            var gObj = UIPackage.CreateObject(packageName, resName);
            if (gObj == null)
            {
                Debug.LogError("[LoadFGUI][UIPackageRes.LoadRes] resource is not found: " + packageName + "." + resName);
                if (finishCall != null)
                {
                    finishCall(null);
                }
                return;
            }
            GComponent com = gObj.asCom;
            if (finishCall != null)
            {
                finishCall(com);
            }
        }

        public void AddDepend(UIPackageRes packageRes) 
        {
            if (dependPachageList.Contains(packageRes)) return;
            dependPachageList.Add(packageRes);

        }
        public void RemoveDepend(UIPackageRes packageRes) 
        {
            if (!dependPachageList.Contains(packageRes)) return;
            dependPachageList.Remove(packageRes);
        }
        public void AddBeDepend(UIPackageRes packageRes) 
        {
            if (beDependPachageList.Contains(packageRes)) return;
            beDependPachageList.Add(packageRes);
        }
        public void RemoveBeDepend(UIPackageRes packageRes) 
        {
            if (!beDependPachageList.Contains(packageRes)) return;
            beDependPachageList.Remove(packageRes);
        }

        public bool IsBeDepend() 
        {
            return beDependPachageList.Count > 0;
        }
    }
}
